package xing.spring.farmework;

import xing.spring.farmework.annotation.*;
import xing.spring.farmework.beanUtil.BeanDefinition;
import xing.spring.farmework.beanUtil.BeanPostProcessor;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyApplicationContext {
    //Class文件进来，基于配置类而不是xml
    private Class  aClass;

    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();

    private Map<String,Object> singletonObjects = new HashMap<>();

    private List<BeanPostProcessor>  beanPostProcessorsList = new ArrayList<>();

    //Spring容器初始化需要做的东西
    public   MyApplicationContext(Class aClass){
        //如果统计时长，可以记录一下容器的启动时间
       this.aClass = aClass;
       //扫描所有的SpringBean,把包含Component注解的Bean生成BeanDefintion对象
       scan(aClass);
       //实例化非懒加载的单例bean
       instanceNoLazySingleton();
    }

    private void instanceNoLazySingleton() {
        for(String beanName : beanDefinitionMap.keySet()){
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //非懒加载的单例Bean
            if(!beanDefinition.getLazy()&&"singleton".equals(beanDefinition.getScope())){
                Object bean = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,bean);
            }
        }
    }

    private void scan(Class aClass){
        ComponentScan annotation = (ComponentScan) aClass.getAnnotation(ComponentScan.class);
        //得到扫描路径Path
        String path = annotation.value();
        //肯定是app
        ClassLoader classLoader = MyApplicationContext.class.getClassLoader();
        URL resource= classLoader.getResource("xing/service");
        File file = new File(resource.getFile());
        for(File f : file.listFiles()){
            //文件class
            //1、class文件----->类加载------>Class对象------->反射去看一下有无注解
            String fileName = f.getAbsolutePath();
            String subString = fileName.substring(fileName.indexOf("xing"),fileName.indexOf(".class"));
            subString = subString.replace("\\",".");
            try {
                    Class<?> myClass = classLoader.loadClass(subString);
                    if(myClass.isAnnotationPresent(Component.class)){
                        if(BeanPostProcessor.class.isAssignableFrom(myClass)){
                            BeanPostProcessor beanPost = null;
                            try {
                                beanPost = (BeanPostProcessor) myClass.newInstance();
                            } catch (InstantiationException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                            beanPostProcessorsList.add(beanPost);
                        }

                    Component component = myClass.getAnnotation(Component.class);
                    String beanName = component.beanName();
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(myClass);
                    boolean isLazy = myClass.isAnnotationPresent(Lazy.class);
                    beanDefinition.setLazy(isLazy);
                    if(myClass.isAnnotationPresent(Scope.class)){
                        Scope scope = myClass.getAnnotation(Scope.class);
                        String value = scope.value();
                        beanDefinition.setScope(value);
                    }else{
                        beanDefinition.setScope("singleton");
                    }
                    beanDefinitionMap.put(beanName,beanDefinition);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            //2、asm技术解析---->解析字节码
            //分支测试分支测试
            String a = "brach_my_test";
            System.out.println(a);
            int d = 3;
            int b = 23;
        }
    }

    public Object getBean(String beanName){
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("prototype")){
            Object bean = createBean(beanName,beanDefinition);
            return bean;
        }else{
            Object bean = singletonObjects.get(beanName);
            if(bean==null){
                bean = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,bean);
            }
            return bean;
        }
    }

    private Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        Object instance = null;
        try {
             //Bean声明周期
             //1、实例化
             //2、填充属性
             //3、初始化
             instance = clazz.newInstance();
             //寻找注入点
             for(Field field : clazz.getDeclaredFields()){
                 if(field.isAnnotationPresent(Autowired.class)) {
                     Autowired autowired = field.getAnnotation(Autowired.class);
                     boolean require = autowired.require();
                     String fieldName = field.getName();
                     Object bean = getBean(fieldName);
                     if(require&&bean==null){
                         throw new NullPointerException();
                     }
                     field.setAccessible(true);
                     field.set(instance,bean);
                 }
             }
             for(BeanPostProcessor beanPostProcessor : beanPostProcessorsList){
                 beanPostProcessor.postProcessAfterInitialization(instance,beanName);
             }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


        return instance;
    }
}
